#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#include <string.h>
#include <string>
#include <unistd.h>
#include <pthread.h>
#include <sys/wait.h>
#include <functional>
#include "Socket.hpp"
#include "InetAddr.h"
using namespace std;

using http_t = function<string(string request)>;

class Tcpsever;

class ThreadData
{
public:
    ThreadData(socket_sptr socket, InetAddr client, Tcpsever *self)
        : _socket(socket), _client(client), _self(self)
    {
    }

public:
    socket_sptr _socket;
    InetAddr _client;
    Tcpsever *_self;
};

class Tcpsever
{
public:
    Tcpsever(uint16_t port, http_t service)
        : _addr("0", port), _listensocket(std::make_unique<TcpSocket>()), _http_service(service), _isrunning(false)
    {
        _listensocket->BuildListenSocket(_addr);
    }

    static void *handler(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *data = static_cast<ThreadData *>(args);
        string request, response;
        int n = data->_socket->Recv(&request); // 收到请求
        if (n > 0)
        {
            response = data->_self->_http_service(request); //处理请求,并得到应答
            data->_socket->Send(response); // 发送应答
        }
        // 处理完，关掉文件描述符
        data->_socket->Close();
        delete data;
        return nullptr;
    }

    void Loop()
    {
        // 4.不能直接接收数据，要先获取连接
        _isrunning = true;
        while (_isrunning)
        {
            InetAddr peeraddr;
            socket_sptr normalsock = _listensocket->AcceptSocket(&peeraddr);
            if (normalsock == nullptr)
                continue;
            // vesion 2:多线程
            pthread_t tid;
            ThreadData *data = new ThreadData(normalsock, InetAddr(peeraddr), this);
            pthread_create(&tid, nullptr, handler, data);
        }
        _isrunning = false;
    }
    ~Tcpsever()
    {
    }

private:
    socket_sptr _listensocket;
    bool _isrunning;
    InetAddr _addr;
    // 上层业务
    http_t _http_service;
};